/*
 *  Copyright 2019-2020  Sun Feng
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.ruibo.modules.weixin.service.impl;

import com.ruibo.exception.BadRequestException;
import com.ruibo.modules.security.security.vo.JwtUser;
import com.ruibo.modules.system.domain.SysDept;
import com.ruibo.modules.system.domain.SysDictData;
import com.ruibo.modules.system.domain.SysRole;
import com.ruibo.modules.system.domain.SysUser;
import com.ruibo.modules.system.repository.SysDictDataRepository;
import com.ruibo.modules.system.repository.SysUserRepository;
import com.ruibo.modules.system.service.SysDeptService;
import com.ruibo.modules.system.service.SysDictDataService;
import com.ruibo.modules.system.service.dto.SysDictDataDto;

import com.ruibo.modules.weixin.config.DustType;
import com.ruibo.modules.weixin.domain.DustReport;
import com.ruibo.modules.weixin.domain.RegionCode;
import com.ruibo.modules.weixin.domain.ReportAttachment;
import com.ruibo.modules.weixin.domain.excel.DustReportExcel;
import com.ruibo.modules.weixin.repository.RegionCodeRepository;
import com.ruibo.modules.weixin.repository.ReportAttachmentRepository;
import com.ruibo.utils.*;
import lombok.RequiredArgsConstructor;
import com.ruibo.modules.weixin.repository.DustReportRepository;
import com.ruibo.modules.weixin.service.DustReportService;
import com.ruibo.modules.weixin.service.dto.DustReportDto;
import com.ruibo.modules.weixin.service.dto.DustReportQueryCriteria;
import com.ruibo.modules.weixin.service.mapstruct.DustReportMapper;
import org.springframework.data.domain.*;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 孙峰
 * @website https://el-admin.vip
 * @description 服务实现
 * @date 2020-11-06
 **/
@Service
@RequiredArgsConstructor
public class DustReportServiceImpl implements DustReportService {

    private final DustReportRepository dustReportRepository;
    private final DustReportMapper dustReportMapper;
    private final ReportAttachmentRepository reportAttachmentRepository;
    private final RegionCodeRepository regionCodeRepository;
    private final SysDictDataRepository sysDictDataRepository;
    private final SysUserRepository sysUserRepository;
    private final SysDictDataService sysDictDataService;
    private final SysDeptService sysDeptService;

    @Override
    public Map<String, Object> queryAll(DustReportQueryCriteria criteria, Pageable pageable) {
        //  根据不同的用户查询寻数据
        Long useId = SecurityUtils.getUseId();
        Optional<SysUser> sysUserOptional = sysUserRepository.findById(useId);
        if (sysUserOptional.isPresent()) {
            SysDept sysDept = sysUserOptional.get().getDept();
            Set<SysRole> sysRoles = sysUserOptional.get().getSysRoles();
            // 获取权限的roleKey
            Set<String> roleKey = sysRoles.stream()
                    .map(SysRole::getRoleKey)
                    .collect(Collectors.toSet());

            if (roleKey.size() > 0) {
                // 说明是管理员用户
                if (roleKey.contains("admin")) {

                } else if (roleKey.contains("level2")) {
                    // 如果查询的不是本级权限数据
                    if (StringUtils.isNotEmpty(criteria.getCityCode()) && !criteria.getCityCode().equals(sysDept.getCityCode())) {
                        PageImpl<DustReport> page = new PageImpl<DustReport>(new ArrayList<>());
                        return PageUtil.toPage(page.map(dustReportMapper::toDto));
                    }
                    // 说明是市级用户   查询本市下所有的数据
                    criteria.setCityCode(sysDept.getCityCode());

                } else if (roleKey.contains("level3")) {

                    // 如果查询的不是本级权限数据
                    if (StringUtils.isNotEmpty(criteria.getCountyCode()) && !criteria.getCountyCode().equals(sysDept.getCountyCode())) {
                        PageImpl<DustReport> page = new PageImpl<DustReport>(new ArrayList<>());
                        return PageUtil.toPage(page.map(dustReportMapper::toDto));
                    }

                    // 说明是县级用户 查询本县的数据
                    criteria.setCityCode(sysDept.getCityCode());
                    criteria.setCountyCode(sysDept.getCountyCode());
                }
            } else {
                throw new BadRequestException("该用户没有权限,请联系管理员");
            }
        } else {
            throw new BadRequestException("用户登录超时");
        }

        // 封装根据创建时间查询
        Sort sort = Sort.by(Sort.Direction.DESC, "createdDate");
        PageRequest pageRequest = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);

        Page<DustReport> page = dustReportRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageRequest);


        return PageUtil.toPage(page.map(dustReportMapper::toDto));
    }

    @Override
    public List<DustReportDto> queryAll(DustReportQueryCriteria criteria) {
        return dustReportMapper.toDto(dustReportRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public DustReportDto findById(Long id) {
        DustReport dustReport = dustReportRepository.findById(id).orElseGet(DustReport::new);
        ValidationUtil.isNull(dustReport.getId(), "DustReport", "id", id);
        // 上报附件信息
        List<ReportAttachment> reportAttachments = reportAttachmentRepository.findByDustReportIdAndRemark(id, "phone");
        DustReportDto reportDto = dustReportMapper.toDto(dustReport);
        reportDto.setReportAttachments(reportAttachments);
        // 反馈附件信息
        List<ReportAttachment> feedbackAttachments = reportAttachmentRepository.findByDustReportIdAndRemark(id, "feedback");
        reportDto.setFeedbackAttachments(feedbackAttachments);
        return reportDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DustReportDto create(DustReportDto resources) {
        DustReport dustReport = new DustReport();
        UpdateUtil.copyNullProperties(resources, dustReport);
        String dateTimeFormat = DateUtils.localDateTimeFormat(LocalDateTime.now(), "yyyyMMddhhmmss");

        // 处理生成编号
        String no = "NO" + dateTimeFormat + (int) (Math.random()) * 100;
        dustReport.setNo(no);
        // 设置城市名称

        setCityCodeAndCityName(dustReport,resources);

        DustReport report = dustReportRepository.save(dustReport);
        List<ReportAttachment> reportAttachments = resources.getReportAttachments();

        // 给附件设置上报案件id
        reportAttachments.forEach(reportAttachment -> {
            reportAttachment.setDustReportId(report.getId());
        });
        reportAttachmentRepository.saveAll(reportAttachments);
        return dustReportMapper.toDto(report);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DustReportDto resources) {
        DustReport dustReport = dustReportRepository.findById(resources.getId()).orElseGet(DustReport::new);
        ValidationUtil.isNull(dustReport.getId(), "DustReport", "id", resources.getId());
        UpdateUtil.copyNullProperties(resources, dustReport);
        List<ReportAttachment> feedbackAttachments = resources.getFeedbackAttachments();

        // 给附件设置上报案件id
        feedbackAttachments.forEach(reportAttachment -> {
            reportAttachment.setDustReportId(dustReport.getId());
        });
        reportAttachmentRepository.saveAll(feedbackAttachments);

        setCityCodeAndCityName(dustReport,resources);

        dustReportRepository.save(dustReport);
    }

    // 设置城市名称

    public void setCityCodeAndCityName( DustReport dustReport,DustReportDto resources){
        // 设置城市名称
        if (null!=resources&&null!=resources.getAreaValue()&&resources.getAreaValue().size() > 0) {
            LinkedList<String> areaValues = resources.getAreaValue();
            dustReport.setCityCode(areaValues.get(0));
            String city = regionCodeRepository.findByRegionCode(areaValues.get(0)).getRegionName();
            dustReport.setCity(city);
            dustReport.setCountyCode(areaValues.get(1));
            String county = regionCodeRepository.findByRegionCode(areaValues.get(1)).getRegionName();
            dustReport.setCounty(county);
        }
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            dustReportRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<DustReportDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (DustReportDto dustReport : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(" createdBy", dustReport.getCreatedBy());
            map.put(" createdDate", dustReport.getCreatedDate().toString());
            map.put(" lastModifiedBy", dustReport.getLastModifiedBy());
            map.put(" lastModifiedDate", dustReport.getLastModifiedDate().toString());
            map.put(" remark", dustReport.getRemark());
            map.put(" version", dustReport.getVersion());
            map.put(" address", dustReport.getAddress());
            map.put(" city", dustReport.getCity());
            map.put(" cityCode", dustReport.getCityCode());
            map.put(" county", dustReport.getCounty());
            map.put(" countyCode", dustReport.getCountyCode());
            map.put(" latitude", dustReport.getLatitude());
            map.put(" longitude", dustReport.getLongitude());
            map.put(" phoneNumber", dustReport.getPhoneNumber());
            map.put(" reportType", dustReport.getReportType());
            map.put(" reporter", dustReport.getReporter());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<DustReport> findByOpenid(String openid) {
        return dustReportRepository.findByOpenid(openid);
    }

    @Override
    public List<DustReportExcel> queryAllForeExcel(DustReportQueryCriteria criteria) {

        //  根据不同的用户查询寻数据
        Long useId = SecurityUtils.getUseId();
        Optional<SysUser> sysUserOptional = sysUserRepository.findById(useId);
        if (sysUserOptional.isPresent()) {
            SysDept sysDept = sysUserOptional.get().getDept();
            Set<SysRole> sysRoles = sysUserOptional.get().getSysRoles();
            // 获取权限的roleKey
            Set<String> roleKey = sysRoles.stream()
                    .map(SysRole::getRoleKey)
                    .collect(Collectors.toSet());
            if (roleKey.size() > 0) {
                // 说明是管理员用户
                if (roleKey.contains("admin")) {
                } else if (roleKey.contains("level2")) {
                    // 如果查询的不是本级权限数据
                    if (StringUtils.isNotEmpty(criteria.getCityCode()) && !criteria.getCityCode().equals(sysDept.getCityCode())) {
                        PageImpl<DustReport> page = new PageImpl<DustReport>(new ArrayList<>());
                        return new ArrayList<>();
                    }
                    // 说明是市级用户   查询本市下所有的数据
                    criteria.setCityCode(sysDept.getCityCode());

                } else if (roleKey.contains("level3")) {
                    // 如果查询的不是本级权限数据
                    if (StringUtils.isNotEmpty(criteria.getCountyCode()) && !criteria.getCountyCode().equals(sysDept.getCountyCode())) {
                        PageImpl<DustReport> page = new PageImpl<DustReport>(new ArrayList<>());
                        return new ArrayList<>();
                    }
                    // 说明是县级用户 查询本县的数据
                    criteria.setCityCode(sysDept.getCityCode());
                    criteria.setCountyCode(sysDept.getCountyCode());
                }
            } else {
                throw new BadRequestException("该用户没有权限,请联系管理员");
            }
        } else {
            throw new BadRequestException("用户登录超时");
        }
        List<DustReport> reportList = dustReportRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));

        List<SysDictDataDto> dataDtoList = sysDictDataService.selectDictDataByType("sys_approval_opinions");
        // 将查询的数据转换成 要导出的excel
        List<DustReportExcel> collect = reportList.stream().map(dustReport -> {
            DustReportExcel dustReportExcel = new DustReportExcel();
            UpdateUtil.copyNullProperties(dustReport, dustReportExcel);
            dustReportExcel.setReportType(DustType.valueOf(dustReport.getReportType()).getDictLabel());

            if (!StringUtils.isEmpty(dustReport.getApprovalOpinions())) {
                SysDictDataDto dataDto = dataDtoList.stream().filter(sysDictDataDto -> sysDictDataDto.getDictValue().equals(dustReport.getApprovalOpinions()))
                        .limit(1).collect(Collectors.toList()).get(0);
                dustReportExcel.setApprovalOpinions(dataDto.getDictLabel());
            }
            dustReportExcel.setReportStatus(dustReport.getReportStatus().equals("1")?"是":"否");
            dustReportExcel.setCreatedDate(dustReport.getCreatedDate().orElse(LocalDateTime.now()).toString());
            return dustReportExcel;
        }).collect(Collectors.toList());
        return collect;
    }
}
